Component({
  data: {
    canvas: null,
    context: null,
    watermarkImage: null,
    watermarkImgSrc: '/assets/images/ic_watermark.png',
    canvasSideLengthLimit: 4096, // canvas 尺寸大于 4096 时，会出现异常
  },

  methods: {
    initCanvas() {
      this.createSelectorQuery()
        .select('#canvas')
        .fields({ node: true })
        .exec((res) => {
          const canvas = res[0].node
          const context = canvas.getContext('2d')
          this.setData({ canvas, context })
          const watermarkImage = canvas.createImage()
          watermarkImage.onload = () => {
            this.setData({ watermarkImage })
          }
          watermarkImage.src = this.data.watermarkImgSrc
        })
    },

    calculateDpr(width, height) {
      const canvasSideLengthLimit = this.data.canvasSideLengthLimit
      const sideLength = Math.max(width, height)
      let dpr = wx.getSystemInfoSync().pixelRatio
      if (sideLength * dpr > canvasSideLengthLimit) {
        dpr = canvasSideLengthLimit / sideLength
      }
      return dpr
    },

    rotate(imagePath, degree) {
      return new Promise((resolve, reject) => {
        if (degree % 90 !== 0) return reject('旋转角度必须是 90 的倍数')
        while (degree < 0) degree += 360
        degree %= 360
        if (degree === 0) return resolve(imagePath)

        if (!this.data.canvas) return reject('canvas 初始化失败')

        const image = this.data.canvas.createImage()
        image.onload = () => {
          try {
            const { canvas, context, canvasSideLengthLimit } = this.data
            const imgWidth = image.width
            const imgHeight = image.height
            const dpr = this.calculateDpr(imgWidth, imgHeight)

            // 根据图片调整 canvas 大小
            if (degree % 180 === 0) {
              canvas.width = Math.min(imgWidth * dpr, canvasSideLengthLimit)
              canvas.height = Math.min(imgHeight * dpr, canvasSideLengthLimit)
            } else {
              canvas.width = Math.min(imgHeight * dpr, canvasSideLengthLimit)
              canvas.height = Math.min(imgWidth * dpr, canvasSideLengthLimit)
            }
            context.scale(dpr, dpr)

            // 旋转并绘制图片
            if (degree % 180 === 0) {
              context.translate(imgWidth * 0.5, imgHeight * 0.5)
            } else {
              context.translate(imgHeight * 0.5, imgWidth * 0.5)
            }
            context.rotate(degree * Math.PI / 180)
            context.drawImage(image, -imgWidth * 0.5, -imgHeight * 0.5, imgWidth, imgHeight)

            // 将 canvas 内容输出成图片
            wx.canvasToTempFilePath({
              canvas,
              success: res => resolve(res.tempFilePath),
              fail: () => reject('canvas 生成图片失败')
            })
          } catch (err) {
            reject('发生异常')
          }
        }
        image.onerror = () => reject('图片加载失败')
        image.src = imagePath
      })
    },

    addWatermark(imagePath, text) {
      return new Promise((resolve, reject) => {
        if (!this.data.canvas) return reject('canvas 初始化失败')

        const image = this.data.canvas.createImage()
        image.onload = () => {
          try {
            const { canvas, context, canvasSideLengthLimit } = this.data
            const imgWidth = image.width
            const imgHeight = image.height
            const dpr = this.calculateDpr(imgWidth, imgHeight)

            // 根据图片调整 canvas 大小
            canvas.width = Math.min(imgWidth * dpr, canvasSideLengthLimit)
            canvas.height = Math.min(imgHeight * dpr, canvasSideLengthLimit)
            context.scale(dpr, dpr)

            // 绘制图片
            context.drawImage(image, 0, 0, imgWidth, imgHeight)

            const paddingHorizontal = Math.min(imgWidth / 20, 30)
            const paddingVertical = Math.min(imgHeight / 20, 30)

            // 绘制图片水印
            if (this.data.watermarkImage) {
              const watermarkWidth = imgWidth / 4 // 图片宽度决定水印宽度
              const watermarkHeight = watermarkWidth / 208 * 60 // 水印宽度决定水印高度
              context.drawImage(
                this.data.watermarkImage,
                paddingHorizontal,
                imgHeight - watermarkHeight * 5 / 6 - paddingVertical, // 水印图片上下各有 1/6 的空白区域
                watermarkWidth,
                watermarkHeight
              )
            }

            // 绘制文本水印
            if (text) {
              const textWidth = imgWidth * 3 / 8 // 图片宽度决定水印宽度
              const fontSize = textWidth / text.length * 1.92 // 中文字符比英文字符大
              context.font = fontSize + 'px sans-serif' // 文本字体
              context.fillStyle = 'white' // 文本颜色
              const metrics = context.measureText(text)
              const fontBoundingBoxDescent = metrics.fontBoundingBoxDescent || fontSize / 4.3
              context.fillText(
                text,
                imgWidth - metrics.width - paddingHorizontal,
                imgHeight - fontBoundingBoxDescent / 2 - paddingVertical
              )
            }

            // 将 canvas 内容输出成图片
            wx.canvasToTempFilePath({
              canvas,
              success: res => resolve(res.tempFilePath),
              fail: () => reject('canvas 生成图片失败')
            })
          } catch (err) {
            console.log(err);
            reject('发生异常')
          }
        }
        image.onerror = () => reject('图片加载失败')
        image.src = imagePath
      })
    },

    rotateAndAddWatermark(imagePath, degree, text) {
      return new Promise((resolve, reject) => {
        if (degree % 90 !== 0) return reject('旋转角度必须是 90 的倍数')
        while (degree < 0) degree += 360
        degree %= 360

        if (!this.data.canvas) return reject('canvas 初始化失败')

        const image = this.data.canvas.createImage()
        image.onload = () => {
          try {
            const { canvas, context, canvasSideLengthLimit } = this.data
            let imgWidth = image.width
            let imgHeight = image.height
            const dpr = this.calculateDpr(imgWidth, imgHeight)

            // 根据图片调整 canvas 大小
            if (degree % 180 === 0) {
              canvas.width = Math.min(imgWidth * dpr, canvasSideLengthLimit)
              canvas.height = Math.min(imgHeight * dpr, canvasSideLengthLimit)
            } else {
              canvas.width = Math.min(imgHeight * dpr, canvasSideLengthLimit)
              canvas.height = Math.min(imgWidth * dpr, canvasSideLengthLimit)
            }
            context.scale(dpr, dpr)

            context.save()

            // 旋转并绘制图片
            if (degree % 180 === 0) {
              context.translate(imgWidth * 0.5, imgHeight * 0.5)
            } else {
              context.translate(imgHeight * 0.5, imgWidth * 0.5)
            }
            context.rotate(degree * Math.PI / 180)
            context.drawImage(image, -imgWidth * 0.5, -imgHeight * 0.5, imgWidth, imgHeight)

            context.restore()

            if (degree % 180 !== 0) {
              // 根据图片的宽高确定水印大小、位置，旋转 90° 或 270° 时，交换宽高
              const temp = imgWidth
              imgWidth = imgHeight
              imgHeight = temp
            }

            const paddingHorizontal = Math.min(imgWidth / 20, 30)
            const paddingVertical = Math.min(imgHeight / 20, 30)

            // 绘制图片水印
            if (this.data.watermarkImage) {
              const watermarkWidth = imgWidth / 4 // 图片宽度决定水印宽度
              const watermarkHeight = watermarkWidth / 208 * 60 // 水印宽度决定水印高度
              context.drawImage(
                this.data.watermarkImage,
                paddingHorizontal,
                imgHeight - watermarkHeight * 5 / 6 - paddingVertical, // 水印图片上下各有 1/6 的空白区域
                watermarkWidth,
                watermarkHeight
              )
            }

            // 绘制文本水印
            if (text) {
              const textWidth = imgWidth * 3 / 8 // 图片宽度决定水印宽度
              const fontSize = textWidth / text.length * 1.92 // 中文字符比英文字符大
              context.font = fontSize + 'px sans-serif' // 文本字体
              context.fillStyle = 'white' // 文本颜色
              const metrics = context.measureText(text)
              const fontBoundingBoxDescent = metrics.fontBoundingBoxDescent || fontSize / 4.3
              context.fillText(
                text,
                imgWidth - metrics.width - paddingHorizontal,
                imgHeight - fontBoundingBoxDescent / 2 - paddingVertical
              )
            }

            // 将 canvas 内容输出成图片
            wx.canvasToTempFilePath({
              canvas,
              success: res => resolve(res.tempFilePath),
              fail: () => reject('canvas 生成图片失败')
            })
          } catch (err) {
            console.log(err);
            reject('发生异常')
          }
        }
        image.onerror = () => reject('图片加载失败')
        image.src = imagePath
      })
    },
  },

  lifetimes: {
    ready() {
      this.initCanvas()
    }
  }
})